<?php namespace App\Http\Controllers\Api;

use App\Exceptions\NotFoundException;
use App\Exceptions\SecurityException;
use App\Exceptions\SignUpException;
use App\Facilitator;
use App\Http\Requests\CheckVerifyCodeForPhoneToAuthSession;
use App\Http\Requests\GetVerifyCodeByEmailRequest;
use App\Http\Requests\GetVerifyCodeByPhoneRequest;
use App\Http\Requests\ResetPasswordByPhone;
use App\Http\Requests\SignInRequest;
use App\Http\Requests\SignUpRequest;
use App\Msg;
use App\Services\SendSms;
use App\Services\Tools;
use App\Services\UserManager;
use App\Services\WikeSms;
use App\Sys;
use App\User;
use App\VerifyCodeByEmail;
use App\VerifyCodeByPhone;
use Illuminate\Mail\Message;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Request;

class AuthController extends ApiController
{
    /**
     * @param GetVerifyCodeByPhoneRequest $request
     * @param $phone
     * @return mixed
     * @throws SecurityException
     */
    public function getVerifyCodeByPhone(GetVerifyCodeByPhoneRequest $request){
        $phone = $request -> get('phone');

        $result = VerifyCodeByPhone::wherePhone($phone)->orderBy('created_at','desc')->first();

        if($result && 60 + $result->created_at->timestamp > time())
            throw new SecurityException(SecurityException::Wait60Seconds);

        VerifyCodeByPhone::wherePhone($phone)->delete();

        $VerifyCodeByPhone = new VerifyCodeByPhone();
        $VerifyCodeByPhone -> phone = $phone;
        $VerifyCodeByPhone -> verify_code = sprintf("%04d", rand(0, 9999));
        $VerifyCodeByPhone -> ip = Request::ip();
        $VerifyCodeByPhone -> ensure_session = '';

        $sendSms = new WikeSms();
        $sendSms->sendSms($phone,$VerifyCodeByPhone->verify_code);

        $VerifyCodeByPhone->save();

        return $this->buildResponse(trans('api.auth.get_verification_code.success'));
    }

    /**
     * 用户注册时获取验证码
     * @param GetVerifyCodeByPhoneRequest $request
     * @return \Illuminate\View\View|\Symfony\Component\HttpFoundation\Response
     * @throws SecurityException
     * @throws SignUpException
     */
    public function getVerifyCodeByPhoneForSignUp(GetVerifyCodeByPhoneRequest $request)
    {
        $phone = $request->get('phone');

        if (User::wherePhone($phone)->exists())
            throw new SignUpException(SignUpException::PhoneExists);

        $latest = VerifyCodeByPhone::wherePhone($phone)->orderBy('created_at', 'desc')->first();

        if ($latest && $latest->created_at->timestamp + 60 > time())
            throw new SecurityException(SecurityException::Wait60Seconds);

        VerifyCodeByPhone::wherePhone($phone)->delete();

        $verifyCodeByPhone                    = new VerifyCodeByPhone();
        $verifyCodeByPhone->phone             = $phone;
        $verifyCodeByPhone->verify_code       = sprintf("%04d", rand(0, 9999));
        $verifyCodeByPhone->ip                = Request::ip();
        $verifyCodeByPhone->save();

        (new SendSms())->sendSms($phone, $verifyCodeByPhone->verify_code);

        return $this->buildResponse(trans('api.auth.get_verification_code.success'));
    }

    /**
     * 通过邮箱获取验证码
     * @param GetVerifyCodeByEmailRequest $request
     * @return \Illuminate\View\View|\Symfony\Component\HttpFoundation\Response
     * @throws SecurityException
     */
    public function getVerifyCodeByEmail(GetVerifyCodeByEmailRequest $request)
    {
        $email = $request ->get('email');
        $result = VerifyCodeByEmail::whereEmail($email)->orderBy('created_at','desc')->first();

        if($result && $result->created_at->timestamp + 60 > time())
            throw new SecurityException(SecurityException::Wait60Seconds);

        VerifyCodeByEmail::whereEmail($email)->delete();

        $verifyCodeByEmail                 = new VerifyCodeByEmail();
        $verifyCodeByEmail->email          = $email;
        $verifyCodeByEmail->verify_code    = sprintf("%04d",rand(0,9999));
        $verifyCodeByEmail->ip             = Request::ip();
        $verifyCodeByEmail->ensure_session = '';

        Mail::raw($verifyCodeByEmail->verify_code,function(Message $message) use ($email){
            $message->from('jollyzhilin@163.com','test');
            $message->to($email)->subject('test');
        });

        $verifyCodeByEmail->save();

        return $this->buildResponse(trans('api.auth.getverifycode.success'));
    }

    /**
     * 验证验证码是否正确
     * @param CheckVerifyCodeForPhoneToAuthSession $request
     * @return \Illuminate\View\View|\Symfony\Component\HttpFoundation\Response
     * @throws SecurityException
     * @throws \Exception
     */
    public function checkVerifyCodeForPhoneToAuthorizeSession(CheckVerifyCodeForPhoneToAuthSession $request){
        $phone             = $request->get('phone');
        $verify_code       = $request->get('verify_code');

        /** @var VerifyCodeByPhone $verifyCodeByPhone */
        $verifyCodeByPhone = VerifyCodeByPhone::wherePhone($phone)->whereVerifyCode($verify_code)->first();
        if(!$verifyCodeByPhone || $verifyCodeByPhone->created_at->timestamp + 60 *15 < time()){
            if($verifyCodeByPhone)$verifyCodeByPhone->delete();
            throw new SecurityException(SecurityException::VerifyCodeNotMatch);
        }

        $verifyCodeByPhone->ensure_session = \Session::getId();
        $verifyCodeByPhone->save();

        return $this->buildResponse(trans('api.auth.authorize_session.success'));
    }

    /**
     * 用户注册
     * @param SignUpRequest $request
     * @return \Illuminate\View\View|\Symfony\Component\HttpFoundation\Response
     * @throws SecurityException
     * @throws SignUpException
     * @throws \Exception
     */
    public function SignUp(SignUpRequest $request){
        $username                   = $request->get('username');
        $email                      = $request->get('email');
        $phone                      = $request->get('phone');
        $password                   = $request->get('password');
        $role                       = $request->get('role');
        $verifyCodeForPhone         = $request->get('verify_code_for_phone');
        $verifyCodeForEmail         = $request->get('verify_code_for_email');

        if($username){
            throw new SecurityException(SecurityException::VerifyCodeNotMatch);
        }

        /** @var VerifyCodeByEmail $verifyCodeByEmail */
        if($email){
            $verifyCodeByEmail = VerifyCodeByEmail::whereEmail($email)->whereVerifyCode($verifyCodeForEmail)->first();
            if(!$verifyCodeByEmail || $verifyCodeByEmail->created_at->timestamp + 60 * 15 < time())
                throw new SecurityException(SecurityException::VerifyCodeNotMatch);
            $verifyCodeByEmail -> delete();
        }

        /** @var VerifyCodeByPhone $verifyCodeByPhone */
        if($phone){
            $verifyCodeByPhone = VerifyCodeByPhone::wherePhone($phone)->whereVerifyCode($verifyCodeForPhone)->first();
            if(!$verifyCodeByPhone || $verifyCodeByPhone->created_at->timestamp + 60 * 15 < time()){
                throw new SecurityException(SecurityException::VerifyCodeNotMatch);
            }
            $verifyCodeByPhone -> delete();
        }

        $user = UserManager::signUp($username,$email,$phone,$password,$role);
        $user ->save();

        $facInfo = new Facilitator();
        $facInfo->invite_num = Str::quickRandom(6);
        $facInfo->user()->associate($user);
        $facInfo->save();

        $msg = new Msg();
        $msg->user_id = $user->id;
        $msg->system_msg = Sys::find(1)->modemsg;
        $msg->save();

        return $this->buildResponse(trans('注册成功'),$user);
    }

    public function SignIn(SignInRequest $request){
        $loginId  = $request->get('login_id');
        $username = $request->get('username');
        $email    = $request->get('email');
        $phone    = $request->get('phone');
        $password = $request->get('password');
        $remember = $request->get('remember');

        if($phone){
            $user = UserManager::signInByPhone($phone,$password,$remember);
        }elseif($email){
            $user = UserManager::signInByEmail($email,$password,$remember);
        }elseif($username){
            $user = UserManager::signInByUsername($username,$password,$remember);
        }else{
            if(Tools::isEmail($loginId))
                $user = UserManager::signInByEmail($loginId,$password,$remember);
            else if(Tools::isPhone($loginId))
                $user = UserManager::signInByPhone($loginId,$password,$remember);
            else
                $user = UserManager::signInByUsername($loginId,$password,$remember);
        }

        return $this->buildResponse(trans('登录成功！'),$user);
    }

    public function SignOut(Guard $guard){
        $guard->logout();
        return $this->buildResponse(trans('退出成功！'));
    }

    public function ResetPasswordByPhone(ResetPasswordByPhone $request){
        $phone       = $request->get('phone');
        $verify_code = $request->get('verification_code');
        $password    = $request->get('password');

        /** @var User $user */
        $user = User::wherePhone($phone)->first();
        if(!$user)
            throw new NotFoundException(NotFoundException::UserNotFound);

        $verifyCodeByPhone = VerifyCodeByPhone::wherePhone($phone)->whereVerifyCode($verify_code)->first();
        if(!$verifyCodeByPhone || $verifyCodeByPhone->created_at->timestamp + 60 * 15 <time())
            throw new SecurityException(SecurityException::VerifyCodeNotMatch);

        $verifyCodeByPhone->delete();

        $user->password = bcrypt($password);
        $user->save();
        return $this->buildResponse(trans('密码重置成功'),$user);
    }
}